package com.example.day26_toupinpush;

import android.hardware.display.DisplayManager;
import android.hardware.display.VirtualDisplay;
import android.media.MediaCodec;
import android.media.MediaCodecInfo;
import android.media.MediaFormat;
import android.media.projection.MediaProjection;
import android.os.Build;
import android.view.Surface;

import java.nio.ByteBuffer;

import androidx.annotation.RequiresApi;

/**
 * Description:
 * Created by Gdu on 2021/1/4 16:55.
 */

public class CodecLiveH265 extends Thread {
    public static final String TAG = "CodecLiveH265";
    private MediaCodec mediaCodec;
    private int width = 720;
    private int height = 1280;

    private MediaProjection mediaProjection;
    private VirtualDisplay virtualDisplay;
    private SocketLive socketLive;

    public static final int NAL_I = 19;
    public static final int NAL_VPS = 32;
    private byte[] vps_sps_pps_buf;

    public CodecLiveH265(SocketLive socketLive, MediaProjection mediaProjection) {
        this.mediaProjection = mediaProjection;
        this.socketLive = socketLive;
    }

    @RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN_MR2)
    public void startLive() {
        try {
            //hevc就是h265
            MediaFormat format = MediaFormat.createVideoFormat(MediaFormat.MIMETYPE_VIDEO_HEVC, width, height);
            format.setInteger(MediaFormat.KEY_COLOR_FORMAT, MediaCodecInfo.CodecCapabilities.COLOR_FormatSurface);
            format.setInteger(MediaFormat.KEY_BIT_RATE, width * height);
            format.setInteger(MediaFormat.KEY_FRAME_RATE, 20);
            format.setInteger(MediaFormat.KEY_I_FRAME_INTERVAL, 1);
            mediaCodec = MediaCodec.createEncoderByType(MediaFormat.MIMETYPE_VIDEO_HEVC);
            mediaCodec.configure(format,null,null,MediaCodec.CONFIGURE_FLAG_ENCODE);
            Surface surface = mediaCodec.createInputSurface();
            virtualDisplay = mediaProjection.createVirtualDisplay("-display",width,height,1,
                    DisplayManager.VIRTUAL_DISPLAY_FLAG_PUBLIC,surface,null,null);
        } catch (Exception e) {
            e.printStackTrace();
        }
        start();
    }

    @Override
    public void run() {
        mediaCodec.start();
        MediaCodec.BufferInfo bufferInfo = new MediaCodec.BufferInfo();
        while (true){
            try {
                int outputBufferId = mediaCodec.dequeueOutputBuffer(bufferInfo, 10000);
                if (outputBufferId >= 0) {
                    //编码好的H265的数据
                    ByteBuffer byteBuffer = mediaCodec.getOutputBuffer(outputBufferId);
                    dealFrame(byteBuffer,bufferInfo);
                    mediaCodec.releaseOutputBuffer(outputBufferId,false);
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

    private void dealFrame(ByteBuffer bb,MediaCodec.BufferInfo bufferInfo){
        int offset = 4;//偏移4位
        if (bb.get(2) == 0x01) {//有些分隔符是00 00 01,所以偏移3位
            offset = 3;
        }
        int type = (bb.get(offset) & 0x7e) >> 1;//获取当前类型的标识
        if (type == NAL_VPS) {//当前帧是VPS帧
            vps_sps_pps_buf = new byte[bufferInfo.size];
            bb.get(vps_sps_pps_buf);//缓存vps,sps,pps的帧数据
        } else if (type == NAL_I) {
            byte[] bytes = new byte[bufferInfo.size];
            bb.get(bytes);
            //把之前缓存的vps数据放到i帧数据前一起发
            byte[] newBuf = new byte[vps_sps_pps_buf.length + bytes.length];
            System.arraycopy(vps_sps_pps_buf, 0, newBuf, 0, vps_sps_pps_buf.length);
            System.arraycopy(bytes, 0, newBuf, vps_sps_pps_buf.length, bytes.length);
            this.socketLive.sendData(newBuf);
        } else {
            byte[] bytes = new byte[bufferInfo.size];
            bb.get(bytes);
            this.socketLive.sendData(bytes);
            //Log.v(TAG,"视频数据 "+ Arrays.toString(bytes));
        }
    }

}
